﻿#include <iostream>
#include <vector>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <future>
#include <atomic>

class ThreadPool {
public:
    ThreadPool(size_t threadCount);
    ~ThreadPool();

    template<typename Func, typename... Args>
    auto enqueue(Func&& f, Args&&... args)
    -> std::future<typename std::result_of<Func(Args...)>::type>;

private:
    void worker();

    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;

    std::mutex queueMutex;
    std::condition_variable condition;
    std::atomic<bool> stop;
};

ThreadPool::ThreadPool(size_t threadCount) : stop(false) {
    for (size_t i = 0; i < threadCount; ++i) {
        workers.emplace_back([this] { this->worker(); });
    }
}

ThreadPool::~ThreadPool() {
    stop = true;
    condition.notify_all();
    for (auto& worker : workers) {
        if (worker.joinable())
            worker.join();
    }
}

void ThreadPool::worker() {
    while (!stop) {
        std::function<void()> task;
        {
            std::unique_lock<std::mutex> lock(queueMutex);
            condition.wait(lock, [this] { return stop || !tasks.empty(); });
            if (stop && tasks.empty())
                return;
            task = std::move(tasks.front());
            tasks.pop();
        }
        task();
    }
}

template<typename Func, typename... Args>
auto ThreadPool::enqueue(Func&& f, Args&&... args)
-> std::future<typename std::result_of<Func(Args...)>::type>
{
    using return_type = typename std::result_of<Func(Args...)>::type;

    auto taskPtr = std::make_shared<std::packaged_task<return_type()>>(
            std::bind(std::forward<Func>(f), std::forward<Args>(args)...)
    );

    std::future<return_type> res = taskPtr->get_future();
    {
        std::lock_guard<std::mutex> lock(queueMutex);
        if (stop)
            throw std::runtime_error("enqueue on stopped ThreadPool");

        tasks.emplace([taskPtr]() { (*taskPtr)(); });
    }
    condition.notify_one();
    return res;
}

int main() {
    ThreadPool pool(2);  // 开2个厨师线程

    // 顾客A点了个任务：计算5+10
    auto futureA = pool.enqueue([](int a, int b) {
        std::this_thread::sleep_for(std::chrono::seconds(2));  // 模拟耗时
        return a + b;
    }, 5, 10);

    // 顾客B点了个任务：打印欢迎语
    pool.enqueue([]() {
        std::cout << "欢迎光临快餐店！" << std::endl;
    });

    // 主线程继续做自己的事
    std::cout << "主线程可以继续工作，不用等任务完成" << std::endl;

    // 等顾客A的订单做好，拿结果
    std::cout << "5 + 10 = " << futureA.get() << std::endl;

    return 0;
}
